/*
 * cjson.c
 *
 *  Created on: Jan 22, 2025
 *      Author: hudong
 */
#include "../include/cjson.h"
#include "../include/except.h"

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>

#define DEFAULT_SYMBOLS_CAPACITY 173

#pragma pack(4)
typedef struct _bitset Bitset;
struct _bitset {
  int size;
  int nsize;
  size_t *bits;
};

typedef struct _vector Vector;
struct _vector {
  int index; // just for clouse
  int length;
  void **items;
};

typedef struct _symbol Symbol;
struct _symbol {
  Symbol *next;
  int hash;
  int length;
  char *string;
};

typedef struct _symtable {
  int capacity;
  int modNum;
  int size;
  Symbol **bucket;
} Symtable;

static Symtable Syms = {0, 0, 0, NULL};

static int BITSW = sizeof(size_t) << 3;

#define __addr__(p, offset) ((char *)(p) + (offset))

#define wordIndex(i) ((i) / BITSW)

#define bitIndex(i) ((i) % BITSW)

#define bitV(x) ((x) != 0 ? 1 : 0)

static int bitset_get(Bitset *bits, int index) {
  if (index < 0 || index >= bits->size)
    return -1;

  size_t *p = bits->bits + wordIndex(index);
  return bitV((*p) & (((size_t)1) << bitIndex(index)));
}

static int bitset_set(Bitset *bits, int index, int v) {
  if (index < 0 || index >= bits->size)
    return -1;

  v = v == 0 ? 0 : 1;
  size_t *p = bits->bits + wordIndex(index);
  size_t mask = ((size_t)1) << bitIndex(index);

  int old = bitV((*p) & mask);

  if (old != v) {
    *p ^= mask;
  }

  return old;
}

static void bitset_fill(Bitset *bits, int v) {
  v = v == 0 ? 0 : 0x0ff;
  memset(bits->bits, v, bits->nsize * sizeof(size_t));
}

static Bitset *bitset_new(int size, char init) {
  size = size <= 0 ? 64 : size;
  int nsize = (size / sizeof(size_t)) + 1;

  int nbytes = sizeof(Bitset) + nsize * sizeof(size_t);
  Bitset *ret = (Bitset *)malloc(nbytes);
  Try.checkAlloc(ret, "Failed to create the Bitset.");

  ret->size = size;
  ret->nsize = nsize;
  ret->bits = (size_t *)__addr__(ret, sizeof(Bitset));
  bitset_fill(ret, init);
  return ret;
}

static int __findMaxPrime(int n) {
  Bitset *bs = bitset_new(n, 1);

  int maxPrime = 0;
  int s = sqrt(n);
  for (int i = 2; i <= s; i++) {
    for (int j = i, k = i * j; k <= n; j++) {
      k = i * j;
      bitset_set(bs, k, 0);
    }
  }
  for (int i = 2; i <= n; i++) {
    if (bitset_get(bs, i) == 1) {
      maxPrime = i;
    }
  }

  free(bs);
  return maxPrime;
}

static Vector *vector_new(int capacity) {
  Vector *new = (Vector *)malloc(sizeof(Vector) + capacity * sizeof(void *));
  Try.checkAlloc(new, "Failed to create the vector.");

  new->index = 0;
  new->length = capacity;
  new->items = (void **)__addr__(new, sizeof(Vector));
  return new;
}

static int sym_hash(const char *s, int size) {
  if (size <= 0)
    return -1;

  int hash = 0;
  for (int i = 0; i < size; i++) {
    hash = hash * 31 + s[i];
  }

  return hash & 0x7fffffff;
}

static Symbol *symbol_new(const char *str, int length, int hash) {
  Symbol *sym = (Symbol *)malloc(sizeof(Symbol) + length + 1);
  Try.checkAlloc(sym, "Failed to create the symbol.");
  sym->length = length;
  sym->string = (char *)sym + sizeof(Symbol);
  memcpy(sym->string, str, length);
  sym->string[length] = '\0';
  sym->hash = hash;
  return sym;
}

static void symtab_resize(int capacity) {
  Syms.capacity = capacity;
  Syms.modNum = __findMaxPrime(capacity);
  Syms.size = 0;
  Syms.bucket = (Symbol **)calloc(capacity, sizeof(Symbol *));
  Try.checkAlloc(Syms.bucket, "Failed to create the symbol table.");
}

static void symtab_checktable() {
  if (Syms.capacity == 0) {
    symtab_resize(DEFAULT_SYMBOLS_CAPACITY);
  }
}

typedef void (*__consumer)(void *item, void *cl);

static void symtab_forEach(__consumer fn, void *clouse) {
  Symbol *sym, *tmp;
  int capacity = Syms.capacity;
  for (int i = 0; i < capacity; i++) {
    sym = Syms.bucket[i];
    while (sym) {
      tmp = sym->next;
      fn(sym, clouse);
      sym = tmp;
    }
  }
}

static void symtab_collect(void *e, void *cl) {
  Vector *array = (Vector *)cl;
  array->items[array->index++] = e;
}

static Vector *symtab_all_symbols() {
  Vector *array = vector_new(Syms.size);
  symtab_forEach(symtab_collect, array);
  return array;
}

static Symbol *symtab_cons(Symbol *car, Symbol *cdr) {
  car->next = cdr;
  return car;
}

static void symtab_add_symbol(Symbol *sym) {
  int index = sym->hash % Syms.modNum;
  Symbol *next = Syms.bucket[index];
  Syms.bucket[index] = symtab_cons(sym, next);
  Syms.size++;
}

static void symtab_checksize() {
  if (Syms.size < Syms.modNum)
    return;

  Vector *vector = symtab_all_symbols();

  free(Syms.bucket);

  int capacity = Syms.capacity + (Syms.capacity >> 1);
  symtab_resize(capacity);

  for (int i = 0; i < vector->length; i++) {
    symtab_add_symbol((Symbol *)(vector->items[i]));
  }

  free(vector);
}

static Symbol *symtab_add(const char *s, int offset, int length) {
  symtab_checktable();

  const char *str = s + offset;
  int hash = sym_hash(str, length);
  int index = hash % Syms.modNum;
  Symbol *sym = NULL;
  int i;
  for (sym = Syms.bucket[index]; sym; sym = sym->next) {
    if (sym->length == length) {
      for (i = 0; i < length && sym->string[i] == str[i];)
        i++;
      if (i == length) {
        return sym;
      }
    }
  }
  sym = Syms.bucket[index];
  Syms.bucket[index] = sym = symtab_cons(symbol_new(str, length, hash), sym);
  Syms.size += 1;
  symtab_checksize();
  return sym;
}

static char *symtab_intern(const char *str) {
  return symtab_add(str, 0, strlen(str))->string;
}

static void symtab_destroy() {
  free(Syms.bucket);
  Syms.bucket = NULL;
  Syms.size = 0;
  Syms.capacity = 0;
  Syms.modNum = 0;
}

/******************************JSON********************************************/
struct __json__ {
  JSON *parent;
  JSON *right;
  JSONValue v;
};
#define P(n) ((n)->parent)
#define L(n) ((n)->v.value.j)
#define R(n) ((n)->right)
#define T(n) ((n)->v.type)
#define K(n) ((n)->v.key)
#define BV(n) ((n)->v.value.b)
#define LV(n) ((n)->v.value.l)
#define FV(n) ((n)->v.value.f)
#define SV(n) ((n)->v.value.s)

static bool __isContainer(JSON *node) {
  return node && (T(node) == jsonOBJECT || T(node) == jsonARRAY);
}

static void json_init() { symtab_checktable(); }

static void json_destroy() { symtab_destroy(); }

static JSON *json_new(JSON *parent, int type) {
  JSON *node = (JSON *)malloc(sizeof(JSON));
  Try.checkAlloc(node, "Failed to create the JSON.");
  P(node) = parent;
  L(node) = NULL;
  R(node) = NULL;
  T(node) = type;
  node->v.reserved = 0;
  return node;
}

static JSON *json_newObject() { return json_new(NULL, jsonOBJECT); }

static JSON *json_newArray() { return json_new(NULL, jsonARRAY); }

static int json_size(JSON *json) {
  JSON *node = L(json);
  int n = 0;
  for (; node; node = R(node), n++)
    ;
  return n;
}

static void json_forEach(JSON *json, consumer_jsv fn, void *clouse) {
  JSON *node = L(json);
  for (; node; node = R(node)) {
    fn(&(node->v), clouse);
  }
}

typedef struct ___travel_env__ TravelEnv;

typedef void (*traveler)(JSON *node, TravelEnv *env);

struct ___travel_env__ {
  JSON *from;
  int stage;
  traveler fn;
  void *cl;
};

enum { P2N = 0, L2N = 1, R2N = 2 };

static JSON *__json_travel(JSON *node, TravelEnv *env) {
  if (node == NULL)
    return NULL;

  if (env->from == node || env->from == P(node)) {

    env->stage = P2N;
    (env->fn)(node, env);

    env->from = node;
    if (__isContainer(node) && L(node)) {
      return L(node);
    } else if (R(node)) {
      return R(node);
    } else {
      return P(node);
    }

  } else if (env->from == L(node)) {
    env->stage = L2N;
    (env->fn)(node, env);

    env->from = node;
    if (R(node)) {
      return R(node);
    } else {
      return P(node);
    }
  } else if (env->from == R(node)) {
    env->stage = R2N;
    (env->fn)(node, env);

    env->from = node;
    return P(node);
  }

  return NULL;
}

static void json_travel(JSON *json, traveler fn, void *cl) {
  JSON *node = json;
  TravelEnv env = {.from = json, .stage = 0, .fn = fn, .cl = cl};
  while (1) {
    node = __json_travel(node, &env);
    if (node == json)
      break;
  }
}

static void __freeNode(JSON *json) {
  if (T(json) == jsonSTRING) {
    free(SV(json));
  }
  P(json) = NULL;
  L(json) = NULL;
  R(json) = NULL;
  free(json);
}
static void __traveler_for_free(JSON *node, TravelEnv *env) {
  if (env->stage == L2N || env->stage == R2N) {
    __freeNode(env->from);
  }
}

static void json_free(JSON *json) {
  json_travel(json, __traveler_for_free, NULL);
  __freeNode(json);
}

static JSON *__first_child(JSON *json) {
  for (; json; json = P(json)) {
    if (R(P(json)) == json)
      return P(json);
  }
  return NULL;
}

static JSON *__last_child(JSON *json) {
  for (; R(json); json = R(json))
    ;
  return json;
}

static JSON *__index_child(JSON *json, int index) {
  JSON *node = json;
  for (int i = 0; i < index; i++) {
    if (R(node) == NULL)
      break;
    node = R(node);
  }
  return node;
}

static JSON *__keyof_child(JSON *json, char *key) {
  char *symkey = symtab_intern(key);
  JSON *node = json;
  for (; node; node = node->right) {
    if (K(node) == symkey)
      return node;
  }
  return NULL;
}

static JSON *__put(JSON *json, char *key, int type) {
  if (T(json) != jsonOBJECT)
    Try.throw(IllegalArgument, "The json is not an object");

  JSON *new = NULL;
  if (L(json)) {
    JSON *last = __last_child(L(json));
    new = json_new(last, type);
    R(last) = new;
  } else {
    new = json_new(json, type);
    L(json) = new;
  }
  K(new) = symtab_intern(key);
  return new;
}

static JSON *__add(JSON *json, int index, int type) {
  if (T(json) != jsonARRAY)
    Try.throw(IllegalArgument, "The json is not an array");

  JSON *new = NULL;
  if (L(json)) {
    if (index < 0) {
      JSON *last = __last_child(L(json));
      new = json_new(last, type);
      R(last) = new;
    } else {
      JSON *after = __index_child(L(json), index);
      if (after == L(json)) {
        new = json_new(json, type);
        L(json) = P(after) = new;
      } else {
        new = json_new(P(after), type);
        R(P(after)) = P(after) = new;
      }
      R(new) = after;
    }
  } else {
    new = json_new(json, type);
    L(json) = new;
  }
  return new;
}

static void json_addBoolByKey(JSON *json, char *key, bool value) {
  JSON *new = __put(json, key, jsonBOOL);
  BV(new) = value;
}
static void json_addLongByKey(JSON *json, char *key, long value) {
  JSON *new = __put(json, key, jsonINTEGER);
  LV(new) = value;
}
static void json_addDoubleByKey(JSON *json, char *key, double value) {
  JSON *new = __put(json, key, jsonDOUBLE);
  FV(new) = value;
}
static void json_addStringByKey(JSON *json, char *key, char *value) {
  JSON *new = __put(json, key, jsonSTRING);
  if (value) {
    int len = strlen(value);
    SV(new) = malloc((len + 1) * sizeof(char));
    memcpy(SV(new), value, len);
    SV(new)[len] = '\0';
  }
}
static JSON *json_addObjectByKey(JSON *json, char *key) {
  return __put(json, key, jsonOBJECT);
}
static JSON *json_addArrayByKey(JSON *json, char *key) {
  return __put(json, key, jsonARRAY);
}
static void json_addBoolByIndex(JSON *json, int index, bool value) {
  JSON *new = __add(json, index, jsonBOOL);
  BV(new) = value;
}
static void json_addLongByIndex(JSON *json, int index, long value) {
  JSON *new = __add(json, index, jsonINTEGER);
  LV(new) = value;
}
static void json_addDoubleByIndex(JSON *json, int index, double value) {
  JSON *new = __add(json, index, jsonDOUBLE);
  FV(new) = value;
}
static void json_addStringByIndex(JSON *json, int index, char *value) {
  JSON *new = __add(json, index, jsonSTRING);
  if (value) {
    int len = strlen(value);
    SV(new) = malloc((len + 1) * sizeof(char));
    memcpy(SV(new), value, len);
    SV(new)[len] = '\0';
  }
}
static JSON *json_addObjectByIndex(JSON *json, int index) {
  return __add(json, index, jsonOBJECT);
}
static JSON *json_addArrayByIndex(JSON *json, int index) {
  return __add(json, index, jsonARRAY);
}
static void json_removeByKey(JSON *json, char *key) {
  if (T(json) != jsonOBJECT)
    return;
  JSON *node = __keyof_child(L(json), key);
  if (node) {
    json_free(node);
    L(json) = NULL;
  }
}
static void json_removeByIndex(JSON *json, int index) {
  if (T(json) != jsonARRAY)
    return;
  JSON *node = __index_child(L(json), index);
  if (node) {
    json_free(node);
    L(json) = NULL;
  }
}
static bool json_getBoolByKey(JSON *json, char *key) {
  if (T(json) != jsonOBJECT)
    Try.throw(IllegalArgument, "The json is not an object.");

  JSON *node = __keyof_child(L(json), key);
  return node ? BV(node) : false;
}
static long json_getLongByKey(JSON *json, char *key) {
  if (T(json) != jsonOBJECT)
    Try.throw(IllegalArgument, "The json is not an object.");

  JSON *node = __keyof_child(L(json), key);
  return node ? LV(node) : 0;
}
static double json_getDoubleByKey(JSON *json, char *key) {
  if (T(json) != jsonOBJECT)
    Try.throw(IllegalArgument, "The json is not an object.");

  JSON *node = __keyof_child(L(json), key);
  return node ? FV(node) : 0;
}
static char *json_getStringByKey(JSON *json, char *key) {
  if (T(json) != jsonOBJECT)
    Try.throw(IllegalArgument, "The json is not an object.");

  JSON *node = __keyof_child(L(json), key);
  return node && T(node) == jsonSTRING ? SV(node) : NULL;
}
static JSON *json_getJSONByKey(JSON *json, char *key) {
  if (T(json) != jsonOBJECT)
    Try.throw(IllegalArgument, "The json is not an object.");

  return __keyof_child(L(json), key);
}

static bool json_getBoolByIndex(JSON *json, int index) {
  if (T(json) != jsonARRAY)
    Try.throw(IllegalArgument, "The json is not an array.");

  JSON *node = __index_child(L(json), index);
  return node ? BV(node) : false;
}
static long json_getLongByIndex(JSON *json, int index) {
  if (T(json) != jsonARRAY)
    Try.throw(IllegalArgument, "The json is not an array.");

  JSON *node = __index_child(L(json), index);
  return node ? LV(node) : 0;
}
static double json_getDoubleByIndex(JSON *json, int index) {
  if (T(json) != jsonARRAY)
    Try.throw(IllegalArgument, "The json is not an array.");

  JSON *node = __index_child(L(json), index);
  return node ? FV(node) : 0;
}
static char *json_getStringByIndex(JSON *json, int index) {
  if (T(json) != jsonARRAY)
    Try.throw(IllegalArgument, "The json is not an array.");

  JSON *node = __index_child(L(json), index);
  return node && T(node) == jsonSTRING ? SV(node) : NULL;
}
static JSON *json_getJSONByIndex(JSON *json, int index) {
  if (T(json) != jsonARRAY)
    Try.throw(IllegalArgument, "The json is not an array.");

  return __index_child(L(json), index);
}
static int json_typeOf(JSON *json) { return json != NULL ? T(json) : -1; }

static JSONValue *json_valueOf(JSON *json) {
  return json != NULL ? &(json->v) : NULL;
}

static bool __is_first_child(JSON *node) {
  return node && P(node) && L(P(node)) == node;
}

typedef void (*consumer_json)(JSON *node, void *clouse);

static void __for_each(JSON *node, consumer_json fn, void *clouse) {
  if (!__isContainer(node))
    return;

  node = L(node);
  for (; node; node = R(node)) {
    fn(node, clouse);
  }
}

static void __stringify(JSON *node, void *cl) {
  if (node == NULL)
    return;

  FILE *os = (FILE *)cl;

  if (!__is_first_child(node)) {
    fputc(',', os);
  }

  if (K(node)) {
    fprintf(os, "\"%s\":", K(node));
  }

  switch (T(node)) {
  case jsonBOOL:
    fprintf(os, "%s", (BV(node) ? "true" : "false"));
    break;
  case jsonINTEGER:
    fprintf(os, "%ld", LV(node));
    break;
  case jsonDOUBLE:
    fprintf(os, "%lf", FV(node));
    break;
  case jsonSTRING:
    fprintf(os, "\"%s\"", SV(node));
    break;
  case jsonOBJECT:
    fputc('{', os);
    __for_each(node, __stringify, os);
    fputc('}', os);
    break;
  case jsonARRAY:
    fputc('[', os);
    __for_each(node, __stringify, os);
    fputc(']', os);
    break;
  }
}

static int json_stringify(JSON *json, FILE *stream) {
  if (!__isContainer(json))
    return 0;

  switch (T(json)) {
  case jsonOBJECT:
    fputc('{', stream);
    __for_each(json, __stringify, stream);
    fputc('}', stream);
    break;
  case jsonARRAY:
    fputc('[', stream);
    __for_each(json, __stringify, stream);
    fputc(']', stream);
    break;
  }
  return ftell(stream);
}

static char __skip_space(FILE *stream) {
  int ch;
  while (isspace(ch = fgetc(stream)))
    ;
  return ch;
}

static void __skip_comment(FILE *stream) {
  int ch, level = 1;
  while ((ch = fgetc(stream)) != EOF) {
    if (ch == '/') {
      ch = fgetc(stream);
      if (ch == '*') {
        level += 1;
      } else if (ch == '/') {
        fseek(stream, -1, SEEK_CUR);
      }
    } else if (ch == '*') {
      ch = fgetc(stream);
      if (ch == '/') {
        level -= 1;
        if (level == 0)
          return;
      } else if (ch == '*') {
        fseek(stream, -1, SEEK_CUR);
      }
    }
  }
}

enum { C, B, I, F, S, K, E };

typedef struct _token Token;
struct _token {
  int type;
  union {
    char c;
    bool b;
    long i;
    double f;
    char *s;
  } value;
};

static void __read_string(FILE *stream, int ch, Token *token) {
  char *buf;
  size_t size;
  FILE *fs = open_memstream(&buf, &size);
  Try.checkAlloc(fs, "Failed to create string buffer");
  char end = ch;
  while ((ch = fgetc(stream)) != EOF) {
    if (ch == end) {
      fclose(fs);
      token->value.s = malloc((size + 1) * sizeof(char));
      memcpy(token->value.s, buf, size);
      token->value.s[size] = '\0';
      free(buf);
      ch = __skip_space(stream);
      fseek(stream, -1, SEEK_CUR);
      if (ch == ':') {
        token->type = K;
      } else {
        token->type = S;
      }
      return;
    } else if (ch != '\\') {
      fputc(ch, fs);
    } else {
      ch = fgetc(stream);
      if (ch == -1)
        Try.throw(-1, "Unexpected EOF for reading string");
      switch (ch) {
      case 'b':
        fputc('\b', fs);
        break;
      case 'f':
        fputc('\f', fs);
        break;
      case 'n':
        fputc('\n', fs);
        break;
      case 'r':
        fputc('\r', fs);
        break;
      case 't':
        fputc('\t', fs);
        break;
      default:
        fputc(ch, fs);
      }
    }
  }
  Try.throw(-1, "Unexpected EOF for reading string");
}

static void __read_value(FILE *stream, int ch, Token *token) {
  char buf[43];
  bool isFloat = false;
  int i = 0;
  buf[i++] = ch;
  while ((ch = fgetc(stream)) != EOF) {
    if (isspace(ch) || ch == ',' || ch == '}' || ch == ']') {
      fseek(stream, -1, SEEK_CUR);
      buf[i] = 0;
      if (isFloat) {
        token->type = F;
        token->value.f = atof(&buf[0]);
      } else {
        token->type = I;
        token->value.i = atol(&buf[0]);
      }
      return;
    } else {
      buf[i++] = ch;
      if (ch == '.' || ch == 'e' || ch == 'E') {
        isFloat = true;
      }
    }
  }
}

static void __read_bool(FILE *stream, int ch, Token *token) {
  token->type = B;

  char buf[4];

  if (ch == 't') {
    buf[0] = fgetc(stream); // r
    buf[1] = fgetc(stream); // u
    buf[2] = fgetc(stream); // e
    if (buf[0] != 'r' && buf[1] != 'u' && buf[2] != 'e')
      Try.throw(-1, "Unexpected char for boolean true");

    token->value.b = true;
  } else {
    buf[0] = fgetc(stream); // a
    buf[1] = fgetc(stream); // l
    buf[2] = fgetc(stream); // s
    buf[3] = fgetc(stream); // e
    if (buf[0] != 'a' || buf[1] != 'l' || buf[2] != 's' || buf[3] != 'e')
      Try.throw(-1, "Unexpected char for boolean false");

    token->value.b = false;
  }
}

static void __next_token(FILE *stream, Token *token) {
  token->type = C;
  char ch;
  while ((ch = __skip_space(stream)) != EOF) {
    switch (ch) {
    case '/':
      ch = fgetc(stream);
      if (ch == '*') {
        __skip_comment(stream);
      } else {
        fseek(stream, -1, SEEK_CUR);
        token->value.c = '/';
        return;
      }
      break;
    case '{':
    case '}':
    case '[':
    case ']':
    case ':':
    case ',':
      token->value.c = ch;
      return;
    case '"':
      __read_string(stream, ch, token);
      return;
    case 't':
    case 'f':
      __read_bool(stream, ch, token);
      return;
    default:
      __read_value(stream, ch, token);
      return;
    }
  }
  token->type = E;
}

static JSON *__root(JSON *node) {
  for (; node && P(node); node = P(node))
    ;
  return node;
}

static JSON *json_parse(FILE *stream) {
  JSON *node = NULL;
  JSON *new;
  Token token = {.type = 0, .value.i = 0};
  while (token.type != E) {
    __next_token(stream, &token);
    switch (token.type) {
    case C:
      switch (token.value.c) {
      case '{':
        if (node == NULL) {
          node = json_new(node, jsonOBJECT);
        } else if (T(node) == -1) {
          T(node) = jsonOBJECT;
        } else {
          new = json_new(node, jsonOBJECT);
          if (L(node) == NULL && node->v.reserved == 0) {
            L(node) = new;
          } else {
            R(node) = new;
          }
          node = new;
        }
        break;
      case '[':
        if (node == NULL) {
          node = json_new(node, jsonARRAY);
        } else if (T(node) == -1) {
          T(node) = jsonARRAY;
        } else {
          new = json_new(node, jsonARRAY);
          if (L(node) == NULL && node->v.reserved == 0) {
            L(node) = new;
          } else {
            R(node) = new;
          }
          node = new;
        }
        break;
      case '}':
      case ']':
        if ((T(node) == jsonOBJECT || T(node) == jsonARRAY) &&
            node->v.reserved == 0) {
          node->v.reserved = 1;
        } else {
          new = __first_child(node);
          new->v.reserved = 1;
          node = new;
        }
        break;
      case ',':
        node->v.reserved = 1;
        break;
      }
      break;
    case K:
      new = json_new(node, -1);
      K(new) = symtab_intern(token.value.s);
      free(token.value.s);
      if (L(node) == NULL && node->v.reserved == 0) {
        L(node) = new;
      } else {
        R(node) = new;
      }
      node = new;
      break;
    case S:
      if (T(node) == -1) {
        T(node) = jsonSTRING;
        SV(node) = token.value.s;
        node->v.reserved = 1;
      } else {
        new = json_new(node, jsonSTRING);
        SV(new) = token.value.s;
        new->v.reserved = 1;
        if (L(node) == NULL && node->v.reserved == 0) {
          L(node) = new;
        } else {
          R(node) = new;
        }
        node = new;
      }
      break;
    case B:
      if (T(node) == -1) {
        T(node) = jsonBOOL;
        BV(node) = token.value.b;
        node->v.reserved = 1;
      } else {
        new = json_new(node, jsonBOOL);
        BV(new) = token.value.b;
        new->v.reserved = 1;
        if (L(node) == NULL && node->v.reserved == 0) {
          L(node) = new;
        } else {
          R(node) = new;
        }
        node = new;
      }
      break;
    case I:
      if (T(node) == -1) {
        T(node) = jsonINTEGER;
        LV(node) = token.value.i;
        node->v.reserved = 1;
      } else {
        new = json_new(node, jsonINTEGER);
        LV(new) = token.value.i;
        new->v.reserved = 1;
        if (L(node) == NULL && node->v.reserved == 0) {
          L(node) = new;
        } else {
          R(node) = new;
        }
        node = new;
      }
      break;
    case F:
      if (T(node) == -1) {
        T(node) = jsonDOUBLE;
        FV(node) = token.value.f;
        node->v.reserved = 1;
      } else {
        new = json_new(node, jsonDOUBLE);
        FV(new) = token.value.f;
        new->v.reserved = 1;
        if (L(node) == NULL && node->v.reserved == 0) {
          L(node) = new;
        } else {
          R(node) = new;
        }
        node = new;
      }
      break;
    }
  }

  return node != NULL ? __root(node) : NULL;
}

#undef _
#define _(m) json_##m
#undef __
#define __(m) .m = _(m)
struct _cjson cjson = {__(init),
                       __(destroy),
                       __(newObject),
                       __(newArray),
                       __(free),
                       __(size),
                       __(forEach),
                       __(addBoolByKey),
                       __(addBoolByIndex),
                       __(addLongByKey),
                       __(addLongByIndex),
                       __(addDoubleByKey),
                       __(addDoubleByIndex),
                       __(addStringByKey),
                       __(addStringByIndex),
                       __(addObjectByKey),
                       __(addObjectByIndex),
                       __(addArrayByKey),
                       __(addArrayByIndex),
                       __(getBoolByKey),
                       __(getBoolByIndex),
                       __(getLongByKey),
                       __(getLongByIndex),
                       __(getDoubleByKey),
                       __(getDoubleByIndex),
                       __(getStringByKey),
                       __(getStringByIndex),
                       __(getJSONByKey),
                       __(getJSONByIndex),
                       __(removeByKey),
                       __(removeByIndex),
                       __(typeOf),
                       __(valueOf),
                       __(stringify),
                       __(parse)};

#pragma pack()
